package com.xzz.service.impl;

import com.xzz.constants.SmsCodeConstants;
import com.xzz.constants.VerifyCodeConstants;
import com.xzz.domain.MessageBucksms;
import com.xzz.domain.MessageSms;
import com.xzz.dto.RedisRegisterDto;
import com.xzz.dto.SmsCodeDto;
import com.xzz.enums.GlobalErrorCode;
import com.xzz.exception.GlobalCustomException;
import com.xzz.service.IMessageBucksmsService;
import com.xzz.service.IMessageSmsService;
import com.xzz.service.IVerifyService;
import com.xzz.util.AssertUtil;
import com.xzz.util.StrUtils;
import com.xzz.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyServiceImpl implements IVerifyService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private IMessageSmsService messageSmsService;

    @Autowired
    private SmsCodeConstants smsCodeConstants;

    @Autowired
    private IMessageBucksmsService messageBucksmsService;

    //图形验证码
    @Override
    public String getImgCode(String key) {
        String code = StrUtils.getComplexRandomString(4);
        redisTemplate.opsForValue().set(key, code, 3, TimeUnit.MINUTES);
        return VerifyCodeUtils.verifyCode(110, 40, code);
    }

    //短信验证码
    @Override
    public void sendSmsCode(SmsCodeDto smsCodeDto) {
        //校验 - 空值校验      注解上用303就可以校验

        //2.校验 - 图片验证码校验
        //2.1.图片验证码是否过期
        Object imageCodeValue = redisTemplate.opsForValue().get(smsCodeDto.getImageCodeKey());
        AssertUtil.isNotNull(imageCodeValue,GlobalErrorCode.IMAGECODEKEY_ERROR);
        //2.2.图片验证码是否正确
        AssertUtil.isEqualsIgnoreCase(imageCodeValue.toString(),smsCodeDto.getImageCode(),GlobalErrorCode.IMAGECODEVALUE_ERROR);

        // 参数为空&电话号码格式校验，使用断言工具进行判断
        String phone = smsCodeDto.getPhone();
        AssertUtil.isPhone(phone, GlobalErrorCode.PHONE_ERROR);

        //扩展：进行黑名单校验
        MessageBucksms buckByPhone = messageBucksmsService.getBuckByPhone(phone);
        AssertUtil.isNull( buckByPhone , GlobalErrorCode.SERVICE_PARAM_IS_BUCK );

        //redis存值格式：key[register:18708146200] : value[code:time]    V用对象代替
        //%S是占位符，用string.format可以直接对占位符替换
        String key = String.format(VerifyCodeConstants.REGISTER_CODE_PREFIX, phone);
        Object codeObj = redisTemplate.opsForValue().get(key);

        String code = null;
        if(codeObj != null){//没有过期
            // 转换对象
            RedisRegisterDto redisRegisterDto = (RedisRegisterDto) codeObj;
            //对比时间
            long intervalTime = System.currentTimeMillis() - redisRegisterDto.getTime();
            if(intervalTime <= smsCodeConstants.getInterval()){ //没过重发时间一分钟
                throw new GlobalCustomException(GlobalErrorCode.REPEATOPERATION_ERROR);
            } else{//过了1分钟
                code = redisRegisterDto.getCode();
            }
        }else{//没有验证码
            code = StrUtils.getRandomString(smsCodeConstants.getCodesize());
        }

        //将验证码数据添加到redis
        RedisRegisterDto ValueCode = new RedisRegisterDto(code, new Date().getTime());
        redisTemplate.opsForValue().set(key, ValueCode, smsCodeConstants.getTimeout(), TimeUnit.MILLISECONDS);
        //发短信
        //SmsUtils.sendSms(phone, "你的验证码为：" + code + "，请在3分钟之内使用!" );  //有次数
        //发送验证码
        String content = String.format(smsCodeConstants.getSmsmessage(), code);
        log.info(content);

        saveMessageSms(code);
    }

    //保存短信到数据库，且发送短信
    private void saveMessageSms(String code) {
        //获得ip地址
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
        String ip = request.getRemoteAddr();

        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(smsCodeConstants.getSmstitle());
        messageSms.setSendTime(new Date());
        messageSms.setContent(code);
        messageSms.setIp(ip);
        // 保存短信信息
        messageSmsService.insert(messageSms);
    }
}